#ifndef LinkedListH
#define LinkedListH
#include "LinkedList.h"
#define null 0

template<class TEntity>
LinkedList<TEntity>::LinkedList()
{
    first = null;
    last = null;
    length = 0;        
}

template<class TEntity>
Node<TEntity>* LinkedList<TEntity>::getFirst()
{
    return first;         
}

template<class TEntity>            
Node<TEntity>* LinkedList<TEntity>::getLast()
{
    return last;               
}

template<class TEntity>  
Node<TEntity>* LinkedList<TEntity>::getNodeByIndex(int index)
{
     if(isEmpty() || index < 0 || index > length)
     {
        return null;             
     }
     Node<TEntity> *tempNode;
     //Si el indice es igual al primero
     if(index == 0)
     {
         tempNode = first;
     //Si el indice es igual al ultimo         
     }else if(index == length)
     {
         tempNode = last;
     //Si el indice es igual al siguiente del primero
     }else if(index == 1)
     {
        tempNode = first->getNext(); 
     //Si el indice es igual al anterior del ultimo      
     }else if(index == (length-1))
     {
         tempNode = last->getPrevious();          
     }
     //Si el indice esta antes del ultimo se busca desde el ultimo
     else if(index/length >= 0.5)
     {
        tempNode = last;
        for(int i=0; tempNode != null; i++)
        {
            if(i == index)
            {
                break;     
            }
            tempNode = tempNode->getPrevious();               
        }  
     }
     //Si no se cumplen los criterios anteriores se hace una busqueda normal
     else
     {
        tempNode = first;
        for(int i=0; tempNode != null; i++)
        {
            if(i == index)
            {
                break;     
            }
            tempNode = tempNode->getNext();               
        }  
     }
     return tempNode;              
}

template<class TEntity> 
TEntity* LinkedList<TEntity>::getByIndex(int index)
{
    return getNodeByIndex(index)->getData();      
}
 
template<class TEntity>              
void LinkedList<TEntity>::add(TEntity *entity)
{
    Node<TEntity> *tempNode = new Node<TEntity>(entity);

    if(first == null)
    {
        first = tempNode;
        last = tempNode;         
    }else
    {
         tempNode->setPrevious(last);
         last->setNext(tempNode);
         last = tempNode;
         length++;     
    }
}
             
template<class TEntity> 
void LinkedList<TEntity>::edit(TEntity *entity, int index)
{
     if(isEmpty() || index > length)
     {
         return;             
     }
     Node<TEntity> *tempNode = getNodeByIndex(index);
     tempNode->setData(entity);
}

template<class TEntity>           
void LinkedList<TEntity>::remove(int index)
{
     if(isEmpty() || index < 0 || index > length)
     {
         return;             
     }
     Node<TEntity> *tempNode = getNodeByIndex(index);
     
     if(tempNode == first)
     {
         first = tempNode->getNext();
         first->setPrevious(null);
     }
     else if(tempNode == last)
     {
         last = tempNode->getPrevious();
         last->setNext(null);
     }
     else
     {
         tempNode->getPrevious()->setNext(tempNode->getNext());
         tempNode->getNext()->setPrevious(tempNode->getPrevious());
     }
     
     tempNode->setNext(null);
     tempNode->setPrevious(null);
     delete tempNode;
     length--;
}
           
template<class TEntity>   
bool LinkedList<TEntity>::isEmpty()
{
    return first == null ? true : false;  
}

template<class TEntity>   
int LinkedList<TEntity>::getLength()
{
    return length;    
}
#endif
